1 Introduction

A cache speeds up the system by reducing latency between the fast and slow medium. The applications of caching are wildly used at different levels in computing system, such as CPU Cache, GPU Cache, Disk Cache, and Web Cache. A cache has limited size and needs an algorithm to decide which elements to replace when it is full. The embedded replacement algorithm is referred to caching policy, or cache replacement policy. When there is request to fetch from the slow medium, the requested element could have existed in the cache. In this scenario, a cache hit is observed. The performance of a caching policy is measured by the cache hit ratio. Many policies have robust performance under some workloads but not the others. This report is to explore the characteristics of different workloads of a CPU cache, and predict the best caching policy to use given the characteristics.

1.1 Caching Policy

This report focuses on 5 caching policies.

1.1.1 Belady

Belady decides the victim to eject by selecting the element with longest reuse distance in the future. Such policy is normally impossible to implement on the real system.

1.1.2 Least Recently Used (LRU)

LRU uses the concept of aging. The policy will eject the oldest element when the cache is full.

1.1.3 Most Recently Used (MRU)

MRU is the opposite of LRU. It also updates the ages, but the youngest element will be ejected.

1.1.4 Pivot

We purpose an idea to find the victim based on the pivot. We cache the address of previous access and set it as the pivot. When the new element comes and need to be inserted into the cache, we check the relative direction to the pivot. If it’s on the left side of the pivot, we eject the right most element. Otherwise if it’s on the right side of the pivot, we eject the left most element.

1.1.5 Longest Distance

We purpose an idea to find the victim by simply choosing the element with the longest distance. If we use address to calculate the distance, the ejected element would be either at the left or right end.

1.2 Workload

We collect the workload using Intel Pin to trace memory access for target programs. We implemented a Pin tool which logs the data access in binary form. To observe more representative memory behavior, we use SPEC CPU 2017 benchmarks.

1.2.1 Perl 500.perlbench_r

This benchmark uses a cut-down version of Perl v5.22.1. The trace file produced by our PIN tool has a big volume (12 GB). Thus we sample random chunks of the trace file to measure the performance of the caching policies. The number under each policy represents number of cache hits. For each row, all policies operate on the same chunk.

dat.500.perlbench_r <- read.csv('../data/500.perlbench_r.csv')
dat.500.perlbench_r
hist(dat.500.perlbench_r$data_size, main='Chunk Size Distribution', 
    xlab='Chunk Size (number of addresses)', col='deepskyblue')

The chunk size is sampled from a uniform distribution. The maximum chunk size is 10k addresses. To make meaningful simulation, we limit the cache size to the number of unique addresses in the chunk. Thus the distribution for the cache sizes are right skewed.

1.2.2 Computational Fluid Dynmaics 519.lbm_r

The program implements “Lattice Boltzmann Method” (LBM) to simulate incompressible fluids in 3D. The trace file produced by our PIN tool has a big volume (32 GB). Thus we sample random chunks of the trace file to measure the performance of the caching policies. The number under each policy represents number of cache hits. For each row, all policies operate on the same chunk.

dat.519.lbm_r <- read.csv('../data/519.lbm_r.csv')
dat.519.lbm_r

1.2.3 Video compression 525.x264_r

The program encodes video streams into H.264/MPEG-4 AVC format. The trace file produced by our PIN tool has a big volume (32 GB). Thus we sample random chunks of the trace file to measure the performance of the caching policies. The number under each policy represents number of cache hits. For each row, all policies operate on the same chunk.

dat.525.x264_r <- read.csv('../data/525.x264_r.csv')
dat.525.x264_r

1.2.4 Pattern Recognition 531.deepsjeng_r

531.deepsjeng_r is based on Deep Sjeng WC2008, the 2008 World Computer Speed-Chess Champion. Deep Sjeng is a rewrite of the older Sjeng-Free program, focused on obtaining the highest possible playing strength. The trace file produced by our PIN tool has a big volume (67 GB). Thus we sample random chunks of the trace file to measure the performance of the caching policies. The number under each policy represents number of cache hits. For each row, all policies operate on the same chunk.

dat.531.deepsjeng_r <- read.csv('../data/531.deepsjeng_r.csv')
dat.531.deepsjeng_r

1.2.5 Fibonacci numbers

This program calculates Fibonacci recursively without memoization. The trace file produced by our PIN tool has a size of 34 MB. Thus we sample random chunks of the trace file to measure the performance of the caching policies. The number under each policy represents number of cache hits. For each row, all policies operate on the same chunk.

dat.fib <- read.csv('../data/fib.csv')
dat.fib

2 Workload Metrics

There are 9 metrics associated with each chuck of the workload.

  • unique_size: Number of unique addresses appeared in the chunk.
  • reads: Number of memory reads.
  • writes: Number of memory writes.
  • avg_step: Average step size. The step size is the absolute difference between two addresses.
  • avg_reuse_dist: Average distance to the next occurrence of the same address.
  • sum_sqrt_count: Sum of the square root of the frequency for each unique address.
  • sum_count: Sum of the of the frequency for each unique address.
  • lis: The length of the longest increasing subsequence.
  • lds: The length of the decreasing increasing subsequence.
add_ratio <- function(dat) {
    dat$unique_ratio <- dat$unique_size / dat$data_size
    dat$read_ratio <- dat$reads / dat$data_size
    dat$write_ratio <- dat$writes / dat$data_size
    dat$sum_sqrt_count_ratio <- dat$sum_sqrt_count / dat$data_size
    dat$sum_count_ratio <- dat$sum_count / dat$data_size
    dat$lis_ratio <- dat$lis / dat$data_size
    dat$lds_ratio <- dat$lds / dat$data_size
    dat$cache_ratio <- dat$cache_size / dat$data_size
    dat$belady_ratio <- (dat$belady + dat$cache_size) / dat$data_size
    dat$lru_ratio <- (dat$lru + dat$cache_size) / dat$data_size
    dat$pivot_ratio <- (dat$pivot + dat$cache_size) / dat$data_size
    dat$ld_ratio <- (dat$ld + dat$cache_size) / dat$data_size
    dat$mru_ratio <- (dat$mru + dat$cache_size) / dat$data_size
    return(dat)
}

dat.500.perlbench_r <- add_ratio(dat.500.perlbench_r)
dat.519.lbm_r <- add_ratio(dat.519.lbm_r)
dat.525.x264_r <- add_ratio(dat.525.x264_r)
dat.531.deepsjeng_r <- add_ratio(dat.531.deepsjeng_r)
dat.fib <- add_ratio(dat.fib)
D <- list(dat.500.perlbench_r, dat.519.lbm_r, dat.525.x264_r, dat.fib, dat.531.deepsjeng_r)
W <- c('Perl', 'LBM', 'Video compression', 'Fibonacci', 'Pattern Recognition')

plot.hist.metric <- function(D, W, metric) {
    par(mfrow=c(3, 2))
    for (i in 1:length(D)) {
        d <- D[[i]][, metric]
        q <- quantile(d, 0.95)
        hist(d[d < q], xlab=metric, main=W[i], col='deepskyblue')
    }
}

2.1 Unique Ratio

plot.hist.metric(D, W, 'unique_ratio')

Unique ratio represents the percentage of unique addresses in the sampled chuck. A lower unique ratio indicates most of the addresses in the chuck are the same. In general, most sampled chucks don’t have many different addresses. Thus a higher unique ratio would be less common, and the frequency decreases. Note the unique ratio could be a multimodal distribution, as some of the plots implied.

2.2 Read Ratio

plot.hist.metric(D, W, 'read_ratio')

Read ratio represents the percentage of the observations involve memory read. Read operations tend to occur in big consecutive chucks. Thus sampled chucks are more likely consist of all reads or none reads.

2.3 Write Ratio

plot.hist.metric(D, W, 'write_ratio')

Write ratio represents the percentage of the observations involve memory write. Write operations are distributed more evenly comparing to memory read operations. Most sampled chucks have low write ratio. It’s less likely to observe a sampled chuck purely consists of memory writes.

2.4 Average Step Size

plot.hist.metric(D, W, 'avg_step')

2.5 Average Reuse Distance

plot.hist.metric(D, W, 'avg_reuse_dist')

2.6 Square-root Count Ratio

plot.hist.metric(D, W, 'sum_sqrt_count_ratio')

2.7 LIS Ratio

plot.hist.metric(D, W, 'lis_ratio')

2.8 LDS Ratio

plot.hist.metric(D, W, 'lds_ratio')

2.9 Hit Ratio

Additionally, the performance of each caching policy is also attached to each chuck. The cache size is specified by cache_size. To create meaningful observations, the cache_size is chosen uniform randomly between 1 and the number of unique addresses (unique_size). The performance of a caching policy is defined by its hit ratio, which is calculated by (H + S) / C, where H is the number of hits, S is the cache size, and C is the size of the chuck.

2.9.1 Perl 500.perlbench_r

plot.policy.hit_ratio <- function(dat, workload) {
    col <- rgb(red=0, green=0, blue=0, alpha=0.2)
    par(mfrow=c(2, 3), pty='s')
    plot(belady_ratio ~ cache_ratio, dat, pch=19, cex=0.5, col=col, main=paste(workload, '- Belady'))
    plot(lru_ratio ~ cache_ratio, dat, pch=19, cex=0.5, col=col, main=paste(workload, '- LRU'))
    plot(pivot_ratio ~ cache_ratio, dat, pch=19, cex=0.5, col=col, main=paste(workload, '- Pivot'))
    plot(ld_ratio ~ cache_ratio, dat, pch=19, cex=0.5, col=col, main=paste(workload, '- LD'))
    plot(mru_ratio ~ cache_ratio, dat, pch=19, cex=0.5, col=col, main=paste(workload, '- MRU'))
}
plot.policy.hit_ratio(dat.500.perlbench_r, 'Perl')

The hit ratio distribution of LRU is closer to the optimal policy - Belady. This plot suggest LRU is more likely to be the best caching policy for this workload.

2.9.2 Computational Fluid Dynmaics 519.lbm_r

plot.policy.hit_ratio(dat.519.lbm_r, 'LBM')

2.9.3 Video compression 525.x264_r

plot.policy.hit_ratio(dat.525.x264_r, 'LBM')

2.9.4 Fibonacci numbers

plot.policy.hit_ratio(dat.fib, 'Fibonacci')

LS0tCnRpdGxlOiAiQ1BVIENhY2hpbmcgUG9saWNpZXMgYW5kIFdvcmtsb2FkIEFuYWx5c2lzIgphdXRob3I6IERvbmFsZCBEb25nCmRhdGU6IE1heSAxMywgMjAxOApvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBjZXJ1bGVhbgogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgojIEludHJvZHVjdGlvbgpBIGNhY2hlIHNwZWVkcyB1cCB0aGUgc3lzdGVtIGJ5IHJlZHVjaW5nIGxhdGVuY3kgYmV0d2VlbiB0aGUgZmFzdCBhbmQgc2xvdyBtZWRpdW0uClRoZSBhcHBsaWNhdGlvbnMgb2YgY2FjaGluZyBhcmUgd2lsZGx5IHVzZWQgYXQgZGlmZmVyZW50IGxldmVscyBpbiBjb21wdXRpbmcgc3lzdGVtLCAKICAgIHN1Y2ggYXMgQ1BVIENhY2hlLCBHUFUgQ2FjaGUsIERpc2sgQ2FjaGUsIGFuZCBXZWIgQ2FjaGUuCkEgY2FjaGUgaGFzIGxpbWl0ZWQgc2l6ZSBhbmQgbmVlZHMgYW4gYWxnb3JpdGhtIHRvIGRlY2lkZSB3aGljaCBlbGVtZW50cyB0byByZXBsYWNlIHdoZW4gaXQgaXMgZnVsbC4KVGhlIGVtYmVkZGVkIHJlcGxhY2VtZW50IGFsZ29yaXRobSBpcyByZWZlcnJlZCB0byBjYWNoaW5nIHBvbGljeSwgb3IgY2FjaGUgcmVwbGFjZW1lbnQgcG9saWN5LgpXaGVuIHRoZXJlIGlzIHJlcXVlc3QgdG8gZmV0Y2ggZnJvbSB0aGUgc2xvdyBtZWRpdW0sIAogIHRoZSByZXF1ZXN0ZWQgZWxlbWVudCBjb3VsZCBoYXZlIGV4aXN0ZWQgaW4gdGhlIGNhY2hlLgpJbiB0aGlzIHNjZW5hcmlvLCBhIGNhY2hlIGhpdCBpcyBvYnNlcnZlZC4KVGhlIHBlcmZvcm1hbmNlIG9mIGEgY2FjaGluZyBwb2xpY3kgaXMgbWVhc3VyZWQgYnkgdGhlICpjYWNoZSBoaXQgcmF0aW8qLgpNYW55IHBvbGljaWVzIGhhdmUgcm9idXN0IHBlcmZvcm1hbmNlIHVuZGVyIHNvbWUgd29ya2xvYWRzIGJ1dCBub3QgdGhlIG90aGVycy4KVGhpcyByZXBvcnQgaXMgdG8gZXhwbG9yZSB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIGRpZmZlcmVudCB3b3JrbG9hZHMgb2YgYSBDUFUgY2FjaGUsCmFuZCBwcmVkaWN0IHRoZSBiZXN0IGNhY2hpbmcgcG9saWN5IHRvIHVzZSBnaXZlbiB0aGUgY2hhcmFjdGVyaXN0aWNzLgoKIyMgQ2FjaGluZyBQb2xpY3kKVGhpcyByZXBvcnQgZm9jdXNlcyBvbiA1IGNhY2hpbmcgcG9saWNpZXMuCgojIyMgQmVsYWR5CkJlbGFkeSBkZWNpZGVzIHRoZSB2aWN0aW0gdG8gZWplY3QgYnkgc2VsZWN0aW5nIHRoZSBlbGVtZW50IHdpdGggbG9uZ2VzdCByZXVzZSBkaXN0YW5jZSBpbiB0aGUgZnV0dXJlLgpTdWNoIHBvbGljeSBpcyBub3JtYWxseSBpbXBvc3NpYmxlIHRvIGltcGxlbWVudCBvbiB0aGUgcmVhbCBzeXN0ZW0uCgojIyMgTGVhc3QgUmVjZW50bHkgVXNlZCAoTFJVKQpMUlUgdXNlcyB0aGUgY29uY2VwdCBvZiBhZ2luZy4gVGhlIHBvbGljeSB3aWxsIGVqZWN0IHRoZSBvbGRlc3QgZWxlbWVudCB3aGVuIHRoZSBjYWNoZSBpcyBmdWxsLgoKIyMjIE1vc3QgUmVjZW50bHkgVXNlZCAoTVJVKQpNUlUgaXMgdGhlIG9wcG9zaXRlIG9mIExSVS4gSXQgYWxzbyB1cGRhdGVzIHRoZSBhZ2VzLCBidXQgdGhlIHlvdW5nZXN0IGVsZW1lbnQgd2lsbCBiZSBlamVjdGVkLgoKIyMjIFBpdm90CldlIHB1cnBvc2UgYW4gaWRlYSB0byBmaW5kIHRoZSB2aWN0aW0gYmFzZWQgb24gdGhlIHBpdm90LiAKV2UgY2FjaGUgdGhlIGFkZHJlc3Mgb2YgcHJldmlvdXMgYWNjZXNzIGFuZCBzZXQgaXQgYXMgdGhlIHBpdm90LgpXaGVuIHRoZSBuZXcgZWxlbWVudCBjb21lcyBhbmQgbmVlZCB0byBiZSBpbnNlcnRlZCBpbnRvIHRoZSBjYWNoZSwKd2UgY2hlY2sgdGhlIHJlbGF0aXZlIGRpcmVjdGlvbiB0byB0aGUgcGl2b3QuIApJZiBpdCdzIG9uIHRoZSBsZWZ0IHNpZGUgb2YgdGhlIHBpdm90LCB3ZSBlamVjdCB0aGUgcmlnaHQgbW9zdCBlbGVtZW50LgpPdGhlcndpc2UgaWYgaXQncyBvbiB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgcGl2b3QsIHdlIGVqZWN0IHRoZSBsZWZ0IG1vc3QgZWxlbWVudC4KCgojIyMgTG9uZ2VzdCBEaXN0YW5jZQpXZSBwdXJwb3NlIGFuIGlkZWEgdG8gZmluZCB0aGUgdmljdGltIGJ5IHNpbXBseSBjaG9vc2luZyB0aGUgZWxlbWVudCB3aXRoIHRoZSBsb25nZXN0IGRpc3RhbmNlLgpJZiB3ZSB1c2UgYWRkcmVzcyB0byBjYWxjdWxhdGUgdGhlIGRpc3RhbmNlLCB0aGUgZWplY3RlZCBlbGVtZW50IHdvdWxkIGJlIGVpdGhlciBhdCB0aGUgbGVmdCBvciByaWdodCBlbmQuCgojIyBXb3JrbG9hZApXZSBjb2xsZWN0IHRoZSB3b3JrbG9hZCB1c2luZyAqSW50ZWwgUGluKiB0byB0cmFjZSBtZW1vcnkgYWNjZXNzIGZvciB0YXJnZXQgcHJvZ3JhbXMuCldlIGltcGxlbWVudGVkIGEgUGluIHRvb2wgd2hpY2ggbG9ncyB0aGUgZGF0YSBhY2Nlc3MgaW4gYmluYXJ5IGZvcm0uClRvIG9ic2VydmUgbW9yZSByZXByZXNlbnRhdGl2ZSBtZW1vcnkgYmVoYXZpb3IsIHdlIHVzZSAqU1BFQyBDUFUgMjAxNyogYmVuY2htYXJrcy4KCiMjIyBQZXJsIFs1MDAucGVybGJlbmNoX3JdKGh0dHBzOi8vd3d3LnNwZWMub3JnL2NwdTIwMTcvRG9jcy9iZW5jaG1hcmtzLzUwMC5wZXJsYmVuY2hfci5odG1sKQpUaGlzIGJlbmNobWFyayB1c2VzIGEgY3V0LWRvd24gdmVyc2lvbiBvZiAqUGVybCB2NS4yMi4xKi4KVGhlIHRyYWNlIGZpbGUgcHJvZHVjZWQgYnkgb3VyIFBJTiB0b29sIGhhcyBhIGJpZyB2b2x1bWUgKDEyIEdCKS4KVGh1cyB3ZSBzYW1wbGUgcmFuZG9tIGNodW5rcyBvZiB0aGUgdHJhY2UgZmlsZSB0byBtZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgY2FjaGluZyBwb2xpY2llcy4KVGhlIG51bWJlciB1bmRlciBlYWNoIHBvbGljeSByZXByZXNlbnRzIG51bWJlciBvZiBjYWNoZSBoaXRzLiAKRm9yIGVhY2ggcm93LCBhbGwgcG9saWNpZXMgb3BlcmF0ZSBvbiB0aGUgc2FtZSBjaHVuay4gCmBgYHtyfQpkYXQuNTAwLnBlcmxiZW5jaF9yIDwtIHJlYWQuY3N2KCcuLi9kYXRhLzUwMC5wZXJsYmVuY2hfci5jc3YnKQpkYXQuNTAwLnBlcmxiZW5jaF9yCmhpc3QoZGF0LjUwMC5wZXJsYmVuY2hfciRkYXRhX3NpemUsIG1haW49J0NodW5rIFNpemUgRGlzdHJpYnV0aW9uJywgCiAgICB4bGFiPSdDaHVuayBTaXplIChudW1iZXIgb2YgYWRkcmVzc2VzKScsIGNvbD0nZGVlcHNreWJsdWUnKQpgYGAKVGhlIGNodW5rIHNpemUgaXMgc2FtcGxlZCBmcm9tIGEgdW5pZm9ybSBkaXN0cmlidXRpb24uClRoZSBtYXhpbXVtIGNodW5rIHNpemUgaXMgMTBrIGFkZHJlc3Nlcy4gVG8gbWFrZSBtZWFuaW5nZnVsIHNpbXVsYXRpb24sCndlIGxpbWl0IHRoZSBjYWNoZSBzaXplIHRvIHRoZSBudW1iZXIgb2YgdW5pcXVlIGFkZHJlc3NlcyBpbiB0aGUgY2h1bmsuClRodXMgdGhlIGRpc3RyaWJ1dGlvbiBmb3IgdGhlIGNhY2hlIHNpemVzIGFyZSByaWdodCBza2V3ZWQuCgojIyMgQ29tcHV0YXRpb25hbCBGbHVpZCBEeW5tYWljcyBbNTE5LmxibV9yXShodHRwczovL3d3dy5zcGVjLm9yZy9jcHUyMDE3L0RvY3MvYmVuY2htYXJrcy81MTkubGJtX3IuaHRtbCkKVGhlIHByb2dyYW0gaW1wbGVtZW50cyAiTGF0dGljZSBCb2x0em1hbm4gTWV0aG9kIiAoTEJNKSB0byBzaW11bGF0ZSBpbmNvbXByZXNzaWJsZSBmbHVpZHMgaW4gM0QuClRoZSB0cmFjZSBmaWxlIHByb2R1Y2VkIGJ5IG91ciBQSU4gdG9vbCBoYXMgYSBiaWcgdm9sdW1lICgzMiBHQikuClRodXMgd2Ugc2FtcGxlIHJhbmRvbSBjaHVua3Mgb2YgdGhlIHRyYWNlIGZpbGUgdG8gbWVhc3VyZSB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIGNhY2hpbmcgcG9saWNpZXMuClRoZSBudW1iZXIgdW5kZXIgZWFjaCBwb2xpY3kgcmVwcmVzZW50cyBudW1iZXIgb2YgY2FjaGUgaGl0cy4gCkZvciBlYWNoIHJvdywgYWxsIHBvbGljaWVzIG9wZXJhdGUgb24gdGhlIHNhbWUgY2h1bmsuIAoKYGBge3J9CmRhdC41MTkubGJtX3IgPC0gcmVhZC5jc3YoJy4uL2RhdGEvNTE5LmxibV9yLmNzdicpCmRhdC41MTkubGJtX3IKYGBgCgojIyMgVmlkZW8gY29tcHJlc3Npb24gWzUyNS54MjY0X3JdKGh0dHBzOi8vd3d3LnNwZWMub3JnL2NwdTIwMTcvRG9jcy9iZW5jaG1hcmtzLzUyNS54MjY0X3IuaHRtbCkKVGhlIHByb2dyYW0gZW5jb2RlcyB2aWRlbyBzdHJlYW1zIGludG8gKkguMjY0L01QRUctNCBBVkMqIGZvcm1hdC4KVGhlIHRyYWNlIGZpbGUgcHJvZHVjZWQgYnkgb3VyIFBJTiB0b29sIGhhcyBhIGJpZyB2b2x1bWUgKDMyIEdCKS4KVGh1cyB3ZSBzYW1wbGUgcmFuZG9tIGNodW5rcyBvZiB0aGUgdHJhY2UgZmlsZSB0byBtZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgY2FjaGluZyBwb2xpY2llcy4KVGhlIG51bWJlciB1bmRlciBlYWNoIHBvbGljeSByZXByZXNlbnRzIG51bWJlciBvZiBjYWNoZSBoaXRzLiAKRm9yIGVhY2ggcm93LCBhbGwgcG9saWNpZXMgb3BlcmF0ZSBvbiB0aGUgc2FtZSBjaHVuay4gCgpgYGB7cn0KZGF0LjUyNS54MjY0X3IgPC0gcmVhZC5jc3YoJy4uL2RhdGEvNTI1LngyNjRfci5jc3YnKQpkYXQuNTI1LngyNjRfcgpgYGAKCiMjIyBQYXR0ZXJuIFJlY29nbml0aW9uIFs1MzEuZGVlcHNqZW5nX3JdKGh0dHBzOi8vd3d3LnNwZWMub3JnL2NwdTIwMTcvRG9jcy9iZW5jaG1hcmtzLzUzMS5kZWVwc2plbmdfci5odG1sKQo1MzEuZGVlcHNqZW5nX3IgaXMgYmFzZWQgb24gRGVlcCBTamVuZyBXQzIwMDgsIHRoZSAyMDA4IFdvcmxkIENvbXB1dGVyIFNwZWVkLUNoZXNzIENoYW1waW9uLiBEZWVwIFNqZW5nIGlzIGEgcmV3cml0ZSBvZiB0aGUgb2xkZXIgU2plbmctRnJlZSBwcm9ncmFtLCBmb2N1c2VkIG9uIG9idGFpbmluZyB0aGUgaGlnaGVzdCBwb3NzaWJsZSBwbGF5aW5nIHN0cmVuZ3RoLgpUaGUgdHJhY2UgZmlsZSBwcm9kdWNlZCBieSBvdXIgUElOIHRvb2wgaGFzIGEgYmlnIHZvbHVtZSAoNjcgR0IpLiAKVGh1cyB3ZSBzYW1wbGUgcmFuZG9tIGNodW5rcyBvZiB0aGUgdHJhY2UgZmlsZSB0byBtZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgY2FjaGluZyBwb2xpY2llcy4gClRoZSBudW1iZXIgdW5kZXIgZWFjaCBwb2xpY3kgcmVwcmVzZW50cyBudW1iZXIgb2YgY2FjaGUgaGl0cy4gRm9yIGVhY2ggcm93LCBhbGwgcG9saWNpZXMgb3BlcmF0ZSBvbiB0aGUgc2FtZSBjaHVuay4KCmBgYHtyfQpkYXQuNTMxLmRlZXBzamVuZ19yIDwtIHJlYWQuY3N2KCcuLi9kYXRhLzUzMS5kZWVwc2plbmdfci5jc3YnKQpkYXQuNTMxLmRlZXBzamVuZ19yCmBgYAoKIyMjIEZpYm9uYWNjaSBudW1iZXJzClRoaXMgcHJvZ3JhbSBjYWxjdWxhdGVzIEZpYm9uYWNjaSByZWN1cnNpdmVseSB3aXRob3V0IG1lbW9pemF0aW9uLgpUaGUgdHJhY2UgZmlsZSBwcm9kdWNlZCBieSBvdXIgUElOIHRvb2wgaGFzIGEgc2l6ZSBvZiAzNCBNQi4KVGh1cyB3ZSBzYW1wbGUgcmFuZG9tIGNodW5rcyBvZiB0aGUgdHJhY2UgZmlsZSB0byBtZWFzdXJlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgY2FjaGluZyBwb2xpY2llcy4KVGhlIG51bWJlciB1bmRlciBlYWNoIHBvbGljeSByZXByZXNlbnRzIG51bWJlciBvZiBjYWNoZSBoaXRzLgpGb3IgZWFjaCByb3csIGFsbCBwb2xpY2llcyBvcGVyYXRlIG9uIHRoZSBzYW1lIGNodW5rLgoKYGBge3J9CmRhdC5maWIgPC0gcmVhZC5jc3YoJy4uL2RhdGEvZmliLmNzdicpCmRhdC5maWIKYGBgCgojIFdvcmtsb2FkIE1ldHJpY3MgClRoZXJlIGFyZSA5IG1ldHJpY3MgYXNzb2NpYXRlZCB3aXRoIGVhY2ggY2h1Y2sgb2YgdGhlIHdvcmtsb2FkLgoKKiBgdW5pcXVlX3NpemVgOiBOdW1iZXIgb2YgdW5pcXVlIGFkZHJlc3NlcyBhcHBlYXJlZCBpbiB0aGUgY2h1bmsuCiogYHJlYWRzYDogTnVtYmVyIG9mIG1lbW9yeSByZWFkcy4KKiBgd3JpdGVzYDogTnVtYmVyIG9mIG1lbW9yeSB3cml0ZXMuCiogYGF2Z19zdGVwYDogQXZlcmFnZSBzdGVwIHNpemUuIFRoZSBzdGVwIHNpemUgaXMgdGhlIGFic29sdXRlIGRpZmZlcmVuY2UgYmV0d2VlbiB0d28gYWRkcmVzc2VzLgoqIGBhdmdfcmV1c2VfZGlzdGA6IEF2ZXJhZ2UgZGlzdGFuY2UgdG8gdGhlIG5leHQgb2NjdXJyZW5jZSBvZiB0aGUgc2FtZSBhZGRyZXNzLgoqIGBzdW1fc3FydF9jb3VudGA6IFN1bSBvZiB0aGUgc3F1YXJlIHJvb3Qgb2YgdGhlIGZyZXF1ZW5jeSBmb3IgZWFjaCB1bmlxdWUgYWRkcmVzcy4KKiBgc3VtX2NvdW50YDogU3VtIG9mIHRoZSBvZiB0aGUgZnJlcXVlbmN5IGZvciBlYWNoIHVuaXF1ZSBhZGRyZXNzLgoqIGBsaXNgOiBUaGUgbGVuZ3RoIG9mIHRoZSBsb25nZXN0IGluY3JlYXNpbmcgc3Vic2VxdWVuY2UuCiogYGxkc2A6IFRoZSBsZW5ndGggb2YgdGhlIGRlY3JlYXNpbmcgaW5jcmVhc2luZyBzdWJzZXF1ZW5jZS4KCmBgYHtyfQphZGRfcmF0aW8gPC0gZnVuY3Rpb24oZGF0KSB7CiAgICBkYXQkdW5pcXVlX3JhdGlvIDwtIGRhdCR1bmlxdWVfc2l6ZSAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCRyZWFkX3JhdGlvIDwtIGRhdCRyZWFkcyAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCR3cml0ZV9yYXRpbyA8LSBkYXQkd3JpdGVzIC8gZGF0JGRhdGFfc2l6ZQogICAgZGF0JHN1bV9zcXJ0X2NvdW50X3JhdGlvIDwtIGRhdCRzdW1fc3FydF9jb3VudCAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCRzdW1fY291bnRfcmF0aW8gPC0gZGF0JHN1bV9jb3VudCAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCRsaXNfcmF0aW8gPC0gZGF0JGxpcyAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCRsZHNfcmF0aW8gPC0gZGF0JGxkcyAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCRjYWNoZV9yYXRpbyA8LSBkYXQkY2FjaGVfc2l6ZSAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCRiZWxhZHlfcmF0aW8gPC0gKGRhdCRiZWxhZHkgKyBkYXQkY2FjaGVfc2l6ZSkgLyBkYXQkZGF0YV9zaXplCiAgICBkYXQkbHJ1X3JhdGlvIDwtIChkYXQkbHJ1ICsgZGF0JGNhY2hlX3NpemUpIC8gZGF0JGRhdGFfc2l6ZQogICAgZGF0JHBpdm90X3JhdGlvIDwtIChkYXQkcGl2b3QgKyBkYXQkY2FjaGVfc2l6ZSkgLyBkYXQkZGF0YV9zaXplCiAgICBkYXQkbGRfcmF0aW8gPC0gKGRhdCRsZCArIGRhdCRjYWNoZV9zaXplKSAvIGRhdCRkYXRhX3NpemUKICAgIGRhdCRtcnVfcmF0aW8gPC0gKGRhdCRtcnUgKyBkYXQkY2FjaGVfc2l6ZSkgLyBkYXQkZGF0YV9zaXplCiAgICByZXR1cm4oZGF0KQp9CgpkYXQuNTAwLnBlcmxiZW5jaF9yIDwtIGFkZF9yYXRpbyhkYXQuNTAwLnBlcmxiZW5jaF9yKQpkYXQuNTE5LmxibV9yIDwtIGFkZF9yYXRpbyhkYXQuNTE5LmxibV9yKQpkYXQuNTI1LngyNjRfciA8LSBhZGRfcmF0aW8oZGF0LjUyNS54MjY0X3IpCmRhdC41MzEuZGVlcHNqZW5nX3IgPC0gYWRkX3JhdGlvKGRhdC41MzEuZGVlcHNqZW5nX3IpCmRhdC5maWIgPC0gYWRkX3JhdGlvKGRhdC5maWIpCkQgPC0gbGlzdChkYXQuNTAwLnBlcmxiZW5jaF9yLCBkYXQuNTE5LmxibV9yLCBkYXQuNTI1LngyNjRfciwgZGF0LmZpYiwgZGF0LjUzMS5kZWVwc2plbmdfcikKVyA8LSBjKCdQZXJsJywgJ0xCTScsICdWaWRlbyBjb21wcmVzc2lvbicsICdGaWJvbmFjY2knLCAnUGF0dGVybiBSZWNvZ25pdGlvbicpCgpwbG90Lmhpc3QubWV0cmljIDwtIGZ1bmN0aW9uKEQsIFcsIG1ldHJpYykgewogICAgcGFyKG1mcm93PWMoMywgMikpCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgoRCkpIHsKICAgICAgICBkIDwtIERbW2ldXVssIG1ldHJpY10KICAgICAgICBxIDwtIHF1YW50aWxlKGQsIDAuOTUpCiAgICAgICAgaGlzdChkW2QgPCBxXSwgeGxhYj1tZXRyaWMsIG1haW49V1tpXSwgY29sPSdkZWVwc2t5Ymx1ZScpCiAgICB9Cn0KYGBgCgojIyBVbmlxdWUgUmF0aW8KYGBge3J9CnBsb3QuaGlzdC5tZXRyaWMoRCwgVywgJ3VuaXF1ZV9yYXRpbycpCmBgYAoKVW5pcXVlIHJhdGlvIHJlcHJlc2VudHMgdGhlIHBlcmNlbnRhZ2Ugb2YgdW5pcXVlIGFkZHJlc3NlcyBpbiB0aGUgc2FtcGxlZCBjaHVjay4KQSBsb3dlciB1bmlxdWUgcmF0aW8gaW5kaWNhdGVzIG1vc3Qgb2YgdGhlIGFkZHJlc3NlcyBpbiB0aGUgY2h1Y2sgYXJlIHRoZSBzYW1lLgpJbiBnZW5lcmFsLCBtb3N0IHNhbXBsZWQgY2h1Y2tzIGRvbid0IGhhdmUgbWFueSBkaWZmZXJlbnQgYWRkcmVzc2VzLgpUaHVzIGEgaGlnaGVyIHVuaXF1ZSByYXRpbyB3b3VsZCBiZSBsZXNzIGNvbW1vbiwgYW5kIHRoZSBmcmVxdWVuY3kgZGVjcmVhc2VzLgpOb3RlIHRoZSB1bmlxdWUgcmF0aW8gY291bGQgYmUgYSBtdWx0aW1vZGFsIGRpc3RyaWJ1dGlvbiwgYXMgc29tZSBvZiB0aGUgcGxvdHMgaW1wbGllZC4KCiMjIFJlYWQgUmF0aW8KYGBge3J9CnBsb3QuaGlzdC5tZXRyaWMoRCwgVywgJ3JlYWRfcmF0aW8nKQpgYGAKClJlYWQgcmF0aW8gcmVwcmVzZW50cyB0aGUgcGVyY2VudGFnZSBvZiB0aGUgb2JzZXJ2YXRpb25zIGludm9sdmUgbWVtb3J5IHJlYWQuClJlYWQgb3BlcmF0aW9ucyB0ZW5kIHRvIG9jY3VyIGluIGJpZyBjb25zZWN1dGl2ZSBjaHVja3MuClRodXMgc2FtcGxlZCBjaHVja3MgYXJlIG1vcmUgbGlrZWx5IGNvbnNpc3Qgb2YgYWxsIHJlYWRzIG9yIG5vbmUgcmVhZHMuCgojIyBXcml0ZSBSYXRpbwpgYGB7cn0KcGxvdC5oaXN0Lm1ldHJpYyhELCBXLCAnd3JpdGVfcmF0aW8nKQpgYGAKCldyaXRlIHJhdGlvIHJlcHJlc2VudHMgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIG9ic2VydmF0aW9ucyBpbnZvbHZlIG1lbW9yeSB3cml0ZS4KV3JpdGUgb3BlcmF0aW9ucyBhcmUgZGlzdHJpYnV0ZWQgbW9yZSBldmVubHkgY29tcGFyaW5nIHRvIG1lbW9yeSByZWFkIG9wZXJhdGlvbnMuCk1vc3Qgc2FtcGxlZCBjaHVja3MgaGF2ZSBsb3cgd3JpdGUgcmF0aW8uIApJdCdzIGxlc3MgbGlrZWx5IHRvIG9ic2VydmUgYSBzYW1wbGVkIGNodWNrIHB1cmVseSBjb25zaXN0cyBvZiBtZW1vcnkgd3JpdGVzLiAKCiMjIEF2ZXJhZ2UgU3RlcCBTaXplCmBgYHtyfQpwbG90Lmhpc3QubWV0cmljKEQsIFcsICdhdmdfc3RlcCcpCmBgYAoKCiMjIEF2ZXJhZ2UgUmV1c2UgRGlzdGFuY2UKYGBge3J9CnBsb3QuaGlzdC5tZXRyaWMoRCwgVywgJ2F2Z19yZXVzZV9kaXN0JykKYGBgCgojIyBTcXVhcmUtcm9vdCBDb3VudCBSYXRpbwpgYGB7cn0KcGxvdC5oaXN0Lm1ldHJpYyhELCBXLCAnc3VtX3NxcnRfY291bnRfcmF0aW8nKQpgYGAKCiMjIExJUyBSYXRpbwpgYGB7cn0KcGxvdC5oaXN0Lm1ldHJpYyhELCBXLCAnbGlzX3JhdGlvJykKYGBgCgoKIyMgTERTIFJhdGlvCmBgYHtyfQpwbG90Lmhpc3QubWV0cmljKEQsIFcsICdsZHNfcmF0aW8nKQpgYGAKCiMjIEhpdCBSYXRpbwoKQWRkaXRpb25hbGx5LCB0aGUgcGVyZm9ybWFuY2Ugb2YgZWFjaCBjYWNoaW5nIHBvbGljeSBpcyBhbHNvIGF0dGFjaGVkIHRvIGVhY2ggY2h1Y2suClRoZSBjYWNoZSBzaXplIGlzIHNwZWNpZmllZCBieSBgY2FjaGVfc2l6ZWAuIFRvIGNyZWF0ZSBtZWFuaW5nZnVsIG9ic2VydmF0aW9ucywgCnRoZSBgY2FjaGVfc2l6ZWAgaXMgY2hvc2VuIHVuaWZvcm0gcmFuZG9tbHkgYmV0d2VlbiAxIGFuZCB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBhZGRyZXNzZXMgKGB1bmlxdWVfc2l6ZWApLgpUaGUgcGVyZm9ybWFuY2Ugb2YgYSBjYWNoaW5nIHBvbGljeSBpcyBkZWZpbmVkIGJ5IGl0cyBoaXQgcmF0aW8sIHdoaWNoIGlzIGNhbGN1bGF0ZWQgYnkKYChIICsgUykgLyBDYCwgd2hlcmUgYEhgIGlzIHRoZSBudW1iZXIgb2YgaGl0cywgYFNgIGlzIHRoZSBjYWNoZSBzaXplLCBhbmQgYENgIGlzIHRoZSBzaXplIG9mIHRoZSBjaHVjay4KCiMjIyBQZXJsIFs1MDAucGVybGJlbmNoX3JdKGh0dHBzOi8vd3d3LnNwZWMub3JnL2NwdTIwMTcvRG9jcy9iZW5jaG1hcmtzLzUwMC5wZXJsYmVuY2hfci5odG1sKQpgYGB7cn0KcGxvdC5wb2xpY3kuaGl0X3JhdGlvIDwtIGZ1bmN0aW9uKGRhdCwgd29ya2xvYWQpIHsKICAgIGNvbCA8LSByZ2IocmVkPTAsIGdyZWVuPTAsIGJsdWU9MCwgYWxwaGE9MC4yKQogICAgcGFyKG1mcm93PWMoMiwgMyksIHB0eT0ncycpCiAgICBwbG90KGJlbGFkeV9yYXRpbyB+IGNhY2hlX3JhdGlvLCBkYXQsIHBjaD0xOSwgY2V4PTAuNSwgY29sPWNvbCwgbWFpbj1wYXN0ZSh3b3JrbG9hZCwgJy0gQmVsYWR5JykpCiAgICBwbG90KGxydV9yYXRpbyB+IGNhY2hlX3JhdGlvLCBkYXQsIHBjaD0xOSwgY2V4PTAuNSwgY29sPWNvbCwgbWFpbj1wYXN0ZSh3b3JrbG9hZCwgJy0gTFJVJykpCiAgICBwbG90KHBpdm90X3JhdGlvIH4gY2FjaGVfcmF0aW8sIGRhdCwgcGNoPTE5LCBjZXg9MC41LCBjb2w9Y29sLCBtYWluPXBhc3RlKHdvcmtsb2FkLCAnLSBQaXZvdCcpKQogICAgcGxvdChsZF9yYXRpbyB+IGNhY2hlX3JhdGlvLCBkYXQsIHBjaD0xOSwgY2V4PTAuNSwgY29sPWNvbCwgbWFpbj1wYXN0ZSh3b3JrbG9hZCwgJy0gTEQnKSkKICAgIHBsb3QobXJ1X3JhdGlvIH4gY2FjaGVfcmF0aW8sIGRhdCwgcGNoPTE5LCBjZXg9MC41LCBjb2w9Y29sLCBtYWluPXBhc3RlKHdvcmtsb2FkLCAnLSBNUlUnKSkKfQpwbG90LnBvbGljeS5oaXRfcmF0aW8oZGF0LjUwMC5wZXJsYmVuY2hfciwgJ1BlcmwnKQpgYGAKClRoZSBoaXQgcmF0aW8gZGlzdHJpYnV0aW9uIG9mIExSVSBpcyBjbG9zZXIgdG8gdGhlIG9wdGltYWwgcG9saWN5IC0gQmVsYWR5LgpUaGlzIHBsb3Qgc3VnZ2VzdCBMUlUgaXMgbW9yZSBsaWtlbHkgdG8gYmUgdGhlIGJlc3QgY2FjaGluZyBwb2xpY3kgZm9yIHRoaXMgd29ya2xvYWQuCgojIyMgQ29tcHV0YXRpb25hbCBGbHVpZCBEeW5tYWljcyBbNTE5LmxibV9yXShodHRwczovL3d3dy5zcGVjLm9yZy9jcHUyMDE3L0RvY3MvYmVuY2htYXJrcy81MTkubGJtX3IuaHRtbCkKYGBge3J9CnBsb3QucG9saWN5LmhpdF9yYXRpbyhkYXQuNTE5LmxibV9yLCAnTEJNJykKYGBgCgojIyMgVmlkZW8gY29tcHJlc3Npb24gWzUyNS54MjY0X3JdKGh0dHBzOi8vd3d3LnNwZWMub3JnL2NwdTIwMTcvRG9jcy9iZW5jaG1hcmtzLzUyNS54MjY0X3IuaHRtbCkKYGBge3J9CnBsb3QucG9saWN5LmhpdF9yYXRpbyhkYXQuNTI1LngyNjRfciwgJ0xCTScpCmBgYAoKIyMjIEZpYm9uYWNjaSBudW1iZXJzCmBgYHtyfQpwbG90LnBvbGljeS5oaXRfcmF0aW8oZGF0LmZpYiwgJ0ZpYm9uYWNjaScpCmBgYAoK